package com.lnu_devteam.zongce.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lnu_devteam.zongce.common.ErrorCode;
import com.lnu_devteam.zongce.common.PageRequest;
import com.lnu_devteam.zongce.constant.PublicityConstant;
import com.lnu_devteam.zongce.constant.ScoreConstant;
import com.lnu_devteam.zongce.exception.BusinessException;
import com.lnu_devteam.zongce.mapper.PublicityMapper;
import com.lnu_devteam.zongce.model.entity.Publicity;
import com.lnu_devteam.zongce.model.entity.Score;
import com.lnu_devteam.zongce.model.entity.User;
import com.lnu_devteam.zongce.model.vo.PublicityVO;
import com.lnu_devteam.zongce.service.PublicityService;
import com.lnu_devteam.zongce.service.ScoreService;
import com.lnu_devteam.zongce.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author xbaoziplus
 * @description 针对表【tb_publicity】的数据库操作Service实现
 * @createDate 2023-04-15 14:23:16
 */
@Service
public class PublicityServiceImpl extends ServiceImpl<PublicityMapper, Publicity>
        implements PublicityService {

    @Resource
    private ScoreService scoreService;

    @Resource
    private UserService userService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 自定义线程池
     */
    /*
    private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
            ThreadPoolConstant.corePoolSize,
            ThreadPoolConstant.maxPoolSize,
            ThreadPoolConstant.keepAliveSeconds,
            ThreadPoolConstant.unit,
            ThreadPoolConstant.workQueue
    );
     */
    @Override
    public boolean publish(String academicYear) {
        int pageIndex = 1;
        int pageSize = 1000;
        //long monthsToSubtract = 6;
        // TODO 可使用线程池优化
        // List<CompletableFuture<Void>> futureList = new ArrayList<>();
        User loginUser = userService.getLoginUser();
        // 使用分布式锁避免多用户重复写库
        String key = PublicityConstant.PUBLICITY_LOCK_KEY_PRE + loginUser.getUCollege();
        if (Boolean.TRUE.equals(stringRedisTemplate.opsForValue().setIfAbsent(key, "1", PublicityConstant.PUBLICITY_TIME, TimeUnit.DAYS))) {
            Publicity publicity = new Publicity();
            // 分块拉取存放，避免OOM
            while (true) {
                Page<Score> blockScorePage = scoreService.page(
                        new Page<>(pageIndex, pageSize),
                        new LambdaQueryWrapper<Score>()
                                .eq(Score::getSStatus, ScoreConstant.AUDIT_APPROVED)
                                .eq(Score::getSCollege, loginUser.getUCollege())
                                .eq(Score::getSAcademicYear, academicYear)
                                //.ge(Score::getUpdateTime, LocalDate.now().minusMonths(monthsToSubtract))
                                .orderByDesc(Score::getUpdateTime)
                );
                // 查询不出数据证明数据查询完毕
                if (blockScorePage.getRecords().size() == 0) {
                    break;
                }
                // 集合转换 TODO 可使用异步优化
                List<Publicity> publicityList = blockScorePage.getRecords().stream().map(item -> {
                    Publicity clone = publicity.clone();
                    BeanUtils.copyProperties(item, clone);
                    return clone;
                }).collect(Collectors.toList());
                this.saveBatch(publicityList);
                // 页数往后
                pageIndex++;
            }
        } else {
            throw new BusinessException(ErrorCode.PUBLICITY_IS_EXIST);
        }
        return true;
    }

    @Override
    public Page<PublicityVO> pagePublicity(PageRequest pageRequest) {
        Page<Publicity> publicityPage = page(
                new Page<>(pageRequest.getCurrentPage(), pageRequest.getPageSize()),
                new LambdaQueryWrapper<Publicity>()
                        .likeRight(StringUtils.isNotBlank(pageRequest.getKey()), Publicity::getCreateUser, pageRequest.getKey())
        );
        Page<PublicityVO> publicityVOPage = new Page<>(pageRequest.getCurrentPage(), pageRequest.getPageSize());
        BeanUtils.copyProperties(publicityPage, publicityVOPage, "records");
        publicityVOPage.setRecords(
                publicityPage.getRecords().stream().map(item -> {
                    PublicityVO publicityVO = new PublicityVO();
                    BeanUtils.copyProperties(item, publicityVO);
                    publicityVO.setUserName(
                            userService.getOne(
                                    new LambdaQueryWrapper<User>().select(User::getUName).eq(User::getUAccount, item.getCreateUser())
                            ).getUName()
                    );
                    return publicityVO;
                }).collect(Collectors.toList())
        );
        return publicityVOPage;
    }
}




